#ifndef GS_EXCEPTIONS_H
#define GS_EXCEPTIONS_H

#include "Config.h"
#include <string>

namespace Gs
{
	// Represents the base Exception class.
	class GS_EXPIMP Exception
	{
	protected:
		std::string _message;

	public:
		// Initialises a new instance of the Exception class.
		Exception();

		// Initialises a new instance of the Exception class.
		Exception(const char *format, ...);

		// Gets the message of the exception.
		const char *GetErrorMessage();
	};

	GS_EXPIMP_TEMPLATE template class GS_EXPIMP std::basic_string<char, std::char_traits<char>, std::allocator<char>>;

	// Thrown when a value cannot be converted to the desired type.
	class GS_EXPIMP InvalidConversionException : public Exception
	{
	public:
		// Initialises a new instance of the InvalidConversionException class.
		InvalidConversionException(const char *from, const char *to);
	};

	// Thrown when an invalid parameter is passed to an API function.
	class GS_EXPIMP InvalidParameterException : public Exception
	{
	public:
		// Initialises a new instance of the InvalidParameterException class.
		InvalidParameterException(const char *param, const char *expected);
	};

	// Thrown when an invalid operation is made.
	class GS_EXPIMP InvalidOperationException : public Exception
	{
	public:
		// Initialises a new instance of the InvalidOperationException class.
		InvalidOperationException(const char *reason);
	};

	// Thrown when an index used is out of the bands of an array.
	class GS_EXPIMP IndexOutOfBoundsException : public Exception
	{
	public:
		// Initialises a new instance of the IndexOutOfBoundsException class.
		IndexOutOfBoundsException();
		
		// Initialises a new instance of the IndexOutOfBoundsException class.
		IndexOutOfBoundsException(const char *reason);
	};

	// Thrown when a runtime error occurs.
	class GS_EXPIMP RuntimeErrorException : public Exception
	{
	public:
		// Initialises a new instance of the RuntimeException class.
		RuntimeErrorException(const char *format, ...);
	};

	// Thrown when a script cannot be compiled due to errors.
	class GS_EXPIMP SyntaxErrorException : public Exception
	{
	private:
		// Stores the line and column indices.
		int _line, _column;

		// Stores the source of the syntax error.
		std::string _source;

	public:
		// Initialises a new instance of the SyntaxErrorException class.
		SyntaxErrorException(int line, int column, const char *source, const char *format, ...);

		// Gets the line index.
		int GetLine();

		// Gets the column index.
		int GetColumn();

		// Gets the source of the syntax error.
		const char *GetSource();
	};

	// Thrown when a file is not found.
	class GS_EXPIMP FileNotFoundException : public Exception
	{
	private:
		// Stores the filename.
		std::string _filename;

	public:
		// Initialises a new instance of the FileNotFoundException class.
		FileNotFoundException(const char *filename);
	};
}

#endif